package cn.peifu.hrm.service.impl;

import cn.peifu.hrm.CourseDoc;
import cn.peifu.hrm.dto.CourseSearchDto;
import cn.peifu.hrm.esmapper.HighlightResultMapper;
import cn.peifu.hrm.repository.CourseElasticsearchRepository;
import cn.peifu.hrm.service.ISearchCourseService;
import cn.peifu.hrm.util.PageList;
import cn.peifu.hrm.vo.AggCourseVo;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class SearchCourseServiceImpl implements ISearchCourseService {

    @Autowired
    private CourseElasticsearchRepository repository;
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;
    @Autowired
    HighlightResultMapper highlightResultMapper;

    @Override
    public PageList<CourseDoc> searchCourse(CourseSearchDto dto) {
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        // 1.封装查询参数dto
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        if(StringUtils.hasLength(dto.getKeyword())){
            queryBuilder.must(QueryBuilders.matchQuery("name",dto.getKeyword()));
        }
        if(dto.getCourseTypeId() != null){
            queryBuilder.filter(QueryBuilders.termQuery("courseTypeId",dto.getCourseTypeId()));
        }
        if(StringUtils.hasLength(dto.getGradeName())){
            queryBuilder.filter(QueryBuilders.termQuery("gradeName",dto.getGradeName()));
        }
        if(dto.getPriceMin() != null){
            queryBuilder.filter(QueryBuilders.rangeQuery("price").gte(dto.getPriceMin()));
        }
        if(dto.getPriceMax() != null){
            queryBuilder.filter(QueryBuilders.rangeQuery("price").lte(dto.getPriceMax()));
        }
        if(StringUtils.hasLength(dto.getTenantName())){
            queryBuilder.must(QueryBuilders.matchQuery("tenantName",dto.getTenantName()));
        }
        // 2.设置查询条件
        //设置高亮显示
        HighlightBuilder.Field field = new HighlightBuilder.Field("name").preTags("<font style='color:red'><b>").postTags("</b></font>");
        builder.withHighlightFields(field);  // 名字高亮
        builder.withQuery(queryBuilder);

        //设置聚合条件
        TermsAggregationBuilder tenantNameAgg = AggregationBuilders
                .terms("tenantNameAgg").field("tenantName").order(Terms.Order.count(false)).size(20);
        TermsAggregationBuilder gradeNameAgg = AggregationBuilders
                .terms("gradeNameAgg").field("gradeName").order(Terms.Order.count(false)).size(20);
        builder.addAggregation(tenantNameAgg).addAggregation(gradeNameAgg);
        //排序
        if(StringUtils.hasLength(dto.getSortField())){
            String filedName = "startTime";
            switch (dto.getSortField().toLowerCase()){
                case "xl": filedName = "saleCount";break;
                case "xp": filedName = "startTime";break;
                case "pl": filedName = "commentCount";break;
                case "jg": filedName = "price";break;
                case "rq": filedName = "viewCount";break;
                default:filedName = "startTime";break;
            }
            SortOrder sortOrder = SortOrder.DESC;
            if(dto.getSortType().equals("asc")){
                sortOrder = SortOrder.ASC;
            }
            builder.withSort(new FieldSortBuilder(filedName).order(sortOrder));
        }
        builder.withPageable(PageRequest.of(dto.getPage()-1,dto.getRows()));

        // 3.执行查询
        /*Page<CourseDoc> page = repository.search(builder.build());*/
        AggregatedPage<CourseDoc> page = elasticsearchTemplate.queryForPage(
                builder.build(),
                CourseDoc.class,
                highlightResultMapper);

        Aggregations aggregations = page.getAggregations();
        Map<String, Aggregation> aggregationMap = aggregations.asMap();

        Set<Map.Entry<String, Aggregation>> entries = aggregationMap.entrySet();
        Map<String,List<AggCourseVo>> aggMap = new HashMap<>();
        entries.forEach(entry -> {
            String key = entry.getKey();
            List<StringTerms.Bucket> buckets = ((StringTerms) entry.getValue()).getBuckets(); // StringTerms强转，才能得到buckets
            List<AggCourseVo> aggCourseVos = buckets.stream().map(bucket -> {
                return new AggCourseVo(bucket.getKeyAsString(), bucket.getDocCount());//将bucket转换成AggCourseVo
            }).collect(Collectors.toList());
            aggMap.put(key,aggCourseVos);
        });
        // 4.返回pagelist
        return new PageList<>(page.getTotalElements(),
                page.getContent(),
                //聚合结果
                aggMap
        );
    }
}
